package zxs.sino.elite.hub.service.impl;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.github.yulichang.base.MPJBaseServiceImpl;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import zxs.sino.elite.hub.utils.PasswordEncoderUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import zxs.sino.elite.hub.constant.RoleConstant;
import zxs.sino.elite.hub.enums.BaseEnum;
import zxs.sino.elite.hub.enums.user.LoginType;
import zxs.sino.elite.hub.enums.user.UserStatus;
import zxs.sino.elite.hub.exception.BizCodeEnums;
import zxs.sino.elite.hub.exception.RRException;
import zxs.sino.elite.hub.mapper.app.AuthMapper;
import zxs.sino.elite.hub.mapper.app.FoldersMapper;
import zxs.sino.elite.hub.mapper.app.UserMapper;
import zxs.sino.elite.hub.model.app.AuthEntity;
import zxs.sino.elite.hub.model.app.FoldersEntity;
import zxs.sino.elite.hub.model.app.UserEntity;
import zxs.sino.elite.hub.model.form.LoginForm;
import zxs.sino.elite.hub.model.form.WXLoginForm;
import zxs.sino.elite.hub.model.model.UserModel;
import zxs.sino.elite.hub.service.UserAuthService;
import zxs.sino.elite.hub.utils.*;


/**
 * @author zhang
 */
@Service("userAuthService")
@RequiredArgsConstructor
public class UserAuthServiceImpl extends MPJBaseServiceImpl<AuthMapper, AuthEntity> implements UserAuthService {

    private final JwtUtil securityUtils;

    private final RedisUtil redisUtil;

    private final WeChatUtil weChatUtil;

    private final AliSMSUtil aliSMSUtil;

    private final UserMapper userMapper;

    private final PasswordEncoderUtil passwordEncoderUtil;

    private final FoldersMapper folderMapper;



    @Override
    @Transactional(rollbackFor = Exception.class)
    public String appletLogin(WXLoginForm wxLoginForm) {

        if (StringUtils.isBlank(wxLoginForm.getLoginCode()) || StringUtils.isBlank(wxLoginForm.getPhoneCode())) {
            throw new RRException(BizCodeEnums.IDEMPOTENT_TOKEN_CREATE_EXCEPTION.getMsg());
        }

        // 1.调用微信接口服务，获取当前微信用户的openId
        String openId = weChatUtil.getOpenId(wxLoginForm.getLoginCode());
        if (openId == null) {
            throw new RRException(BizCodeEnums.IDEMPOTENT_TOKEN_CREATE_EXCEPTION.getMsg());
        }

        // 2.根据获取的openId查询数据是否存在
        LoginForm auth = this.baseMapper.queryUser4AuthKey(LoginType.WECHAT.getCode(), openId);

        // 3.数据库查询结果为空，完成用户注册处理
        if (auth == null) {
            auth = new LoginForm();
            Long userId = registerUser(LoginType.WECHAT.getCode());
            auth.setUserId(userId);

            auth.setAuthKey(openId);
            createAuth(LoginType.WECHAT.getCode(), auth);

            String phone = weChatUtil.getPhoneNumber(wxLoginForm.getPhoneCode());
            if (StringUtils.isBlank(phone)) {
                throw new RRException(BizCodeEnums.IDEMPOTENT_TOKEN_CREATE_EXCEPTION.getMsg());
            }
            auth.setAuthKey(phone);
            createAuth(LoginType.PHONE.getCode(), auth);

            createDefaultFolder(auth.getUserId());
        } else {
            if (UserStatus.isOff(auth.getStatus())) {
                throw new RRException(BizCodeEnums.IDEMPOTENT_TOKEN_CREATE_EXCEPTION.getMsg());
            }
        }

        // 4.用户存在生成Jwt令牌
        String token = securityUtils.generateToken(new UserModel(auth.getUserId(), openId, RoleConstant.USER));

        // 6.将Jwt令牌存储到redis中，并设置过期时间为1天
        redisUtil.set(RedisKeys.getRoleKey(RoleConstant.USER, openId), token, 24 * 60 * 60);

        return token;
    }

    /**
     * 发送短信登录验证码
     *
     * @param phone 验证手机号
     */
    @Override
    public void sendPhoneCode(String phone) {
        // 1.先校验redis中是否存在该邮箱对应的验证码
        String code = (String) redisUtil.get(RedisKeys.getLoginCodeKey(LoginType.PHONE.getValue(), phone));
        if (code != null) {
            throw new RRException(BizCodeEnums.SMS_CODE_EXCEPTION.getMsg());
        }

        // 2.生成验证码
        code = (Math.random() + "").substring(2, 2 + 6);

        // 3.发送短信验证码
        aliSMSUtil.doSendSMSCode(phone, code);

        // 4.将生成的验证码存储到redis中，并设置过期时间为5分钟
        redisUtil.set(RedisKeys.getLoginCodeKey(LoginType.PHONE.getValue(), phone), code, 5 * 60);
    }

    /**
     * 微信小程序外登录
     *
     * @param loginType 登录方式
     * @param loginForm  登录验证内容
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String login(int loginType, LoginForm loginForm) {

        if (!StringUtils.isEmpty(loginForm.getCode()) && !StringUtils.isEmpty(loginForm.getAuthPassword())){
            throw new RRException(BizCodeEnums.VALID_EXCEPTION.getMsg());
        }

        if (StringUtils.isEmpty(loginForm.getCode()) && StringUtils.isEmpty(loginForm.getAuthPassword())){
            throw new RRException(BizCodeEnums.VALID_EXCEPTION.getMsg());
        }

        // 1.根据登录验证识别查询数据是否存在
        LoginForm auth = this.baseMapper.queryUser4AuthKey(loginType, loginForm.getAuthKey());

        // 2.当用户使用手机号+验证码登录时
        if (!StringUtils.isEmpty(loginForm.getCode()) && StringUtils.isEmpty(loginForm.getAuthPassword())) {
            String code = (String) redisUtil.get(RedisKeys.getLoginCodeKey(BaseEnum.getValueByCode(LoginType.class, loginType), loginForm.getAuthKey()));
            // 2.1.redis中验证码失效
            if (code == null) {
                throw new RRException(BizCodeEnums.CODE_EXPIRED_EXCEPTION.getMsg());
            }

            // 2.2.验证码校验失败
            if (!loginForm.getCode().equals(code)) {
                throw new RRException(BizCodeEnums.CODE_ERROR_EXCEPTION.getMsg());
            }

            // 2.3.用户是否存在
            if (auth == null) {
                auth = new LoginForm();
                Long userId = registerUser(loginType);
                auth.setUserId(userId);

                createAuth(loginType, auth);

                createDefaultFolder(auth.getUserId());
            }
        }
        // 3.当用户使用手机号+密码登录时
        else if (StringUtils.isEmpty(loginForm.getCode()) && !StringUtils.isEmpty(loginForm.getAuthPassword())) {
            //账号不存在、密码错误
            if (auth == null || !passwordEncoderUtil.matches(loginForm.getAuthPassword(), auth.getAuthPassword())) {
                throw new RRException(BizCodeEnums.LOGIN_PASSWORD_EXCEPTION.getMsg());
            }
        }

        //账号锁定
        if(auth.getStatus()  ==  0){
            throw new RRException(BizCodeEnums.ACCOUNT_LOCKED_EXCEPTION.getMsg());
        }

        // 4.用户存在生成Jwt令牌
        String token = securityUtils.generateToken(new UserModel(auth.getUserId(), auth.getAuthKey(), RoleConstant.USER));

        // 5.将Jwt令牌存储到redis中，并设置过期时间为1天
        redisUtil.set(RedisKeys.getRoleKey(RoleConstant.USER, loginForm.getAuthKey()), token, 24 * 60 * 60);
        return token;

    }

    /**
     * 更新用户登录密码
     *
     * @param loginForm 登录验证内容
     */
    @Override
    public void updatePassword(LoginForm loginForm) {
        // 使用PasswordEncoderUtil加密新密码
        String newPassword = passwordEncoderUtil.encode(loginForm.getAuthPassword());

        // 3.更新验证表
        LambdaUpdateWrapper<AuthEntity> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(AuthEntity::getSalt, null)
                .set(AuthEntity::getAuthPassword, newPassword)
                .eq(AuthEntity::getAuthKey, loginForm.getAuthKey());
        this.update(updateWrapper);
    }

    /**
     * 用户退出
     */
    @Override
    public void logout() {
        UserModel userInfo = UserContext.getUserInfo();
        redisUtil.delete(RedisKeys.getRoleKey(userInfo.getRole(), userInfo.getAuthKey()));
        // 清除用户上下文
        UserContext.clear();
    }

    /**
     * 注册用户
     *
     * @param createType 认证区分
     */
    private Long registerUser(Integer createType) {
        String userIdStr = "";
        try {
            userIdStr = GeneratorUtil.generateUserId();
        } catch (Exception ignored) {

        }

        //注册用户
        Long userId = Long.valueOf(userIdStr);
        UserEntity user = new UserEntity();
        user.setUserId(userId);
        user.setNickname(BaseEnum.getValueByCode(LoginType.class, createType) + "_" + userId);
        user.setAvatarUrl("https://zxs-lyblog.oss-cn-hangzhou.aliyuncs.com/user-header/20250629233813.jpg");
        user.setStatus(UserStatus.ON.getCode());
        user.setCreateType(BaseEnum.getValueByCode(LoginType.class, createType));
        userMapper.insert(user);

        return userId;
    }

    /**
     * 注册认证登录
     *
     * @param createType 认证区分
     * @param loginForm   认证
     */
    private void createAuth(Integer createType, LoginForm loginForm) {
        AuthEntity auth = new AuthEntity();
        auth.setUserId(loginForm.getUserId());
        auth.setAuthKey(loginForm.getAuthKey());
        auth.setAuthPassword(loginForm.getAuthPassword());
        auth.setSalt(loginForm.getSalt());
        auth.setAuthType(createType);
        this.save(auth);
    }

    /**
     * 创建默认收藏夹
     *
     */
    private void createDefaultFolder(Long userId) {
        FoldersEntity folder = new FoldersEntity();
        folder.setUserId(userId);
        folder.setFolderName("默认收藏夹");
        folderMapper.insert(folder);
    }

}